package rad.framework.jpa;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.EntityManager;

import org.apache.commons.lang.StringUtils;
import org.jboss.seam.Component;
import org.jboss.seam.contexts.Context;

public class EntityHandle implements Serializable {
	private static final long serialVersionUID = 1L;

	private String persistenceContextName;
	private String className;
	private Object id;
	transient private Class clazz;

	public EntityHandle(String persistenceContextName, Class clazz, Object id) {
		this.persistenceContextName = persistenceContextName;
		this.clazz = clazz;
		this.className = clazz.getName();
		this.id = id;
		assert clazz.isAnnotationPresent(Entity.class) : clazz + " is not an @Entity";
	}

	public EntityHandle(String persistenceContextName, Object entity) {
		this(persistenceContextName, entity.getClass(), JpaUtil
				.getIdentity((Serializable) entity));
	}

	public EntityHandle(String value) {
		this(split(value)[0], forName(split(value)[1]),
				valueOf(split(value)[2]));
	}

	//---------------------------------------------------------------

	public Object find() {
		return getEntityManager().find(clazz, id);
	}

	public void put(Context context) {
		put(context, getDefaultVariableName());
	}

	public void put(Context context, String name) {
		context.set(name, find());
	}

	//---------------------------------------------------------------

	public String getType() {
		return clazz.getSimpleName();
	}

	public Object getId() {
		return id;
	}

	public String getDefaultVariableName() {
		return StringUtils.uncapitalize(getType());
	}

	public String toString() {
		return persistenceContextName + ":" + className + ":" + id;
	}

	//---------------------------------------------------------------

	protected EntityManager getEntityManager() {
		return (EntityManager) Component.getInstance(persistenceContextName);
	}
	
	static protected String[] split(String value) {
		return value.split(":");
	}

	static protected Object valueOf(String value) {
		try {
			return Long.valueOf(value);
		} catch(NumberFormatException e) {
			// TODO other formats ???
			return value;
		}
	}

	static protected Class forName(String name) {
		try {
			return Class.forName(name);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
}
